import Konva from 'konva'

export class StageOptionClass {
  stage
  layer
  tr
  setSelectDom
  selectionRectangle
  constructor(stage, layer, setSelectDom) {
    this.stage = stage,
    this.layer = layer
    this.setSelectDom = setSelectDom

    this.tr = new Konva.Transformer()
    this.layer.add(this.tr)

    // 添加选择区域
    this.selectionRectangle = new Konva.Rect({
      fill: 'rgba(0, 0, 255, 0.5)',
      visible: false,
      // disable events to not interrupt with events
      listening: false,
      className: 'selectionRectangle'
    })
    this.layer.add(this.selectionRectangle)
    this.stageSelectListening()
  }

  /**
   * 鼠标拖动矩形框以选中图形
   * 这一段代码是复制官网示例然后进行修改。
   * @address https://konvajs.org/docs/select_and_transform/Basic_demo.html
   */
  stageSelectListening() {
    const self = this
    let x1, y1, x2, y2, selecting = false
    self.stage.on('mousedown', (e) => {
      if (e.target !== self.stage) {
        return
      }
      e.evt.preventDefault()
      x1 = self.stage.getPointerPosition().x
      y1 = self.stage.getPointerPosition().y
      x2 = self.stage.getPointerPosition().x
      y2 = self.stage.getPointerPosition().y

      self.selectionRectangle.width(0)
      self.selectionRectangle.height(0)
      selecting = true
    })

    self.stage.on('mousemove touchmove', (e) => {
      if (!selecting) {
        return
      }
      e.evt.preventDefault();
      x2 = self.stage.getPointerPosition().x
      y2 = self.stage.getPointerPosition().y

      self.selectionRectangle.setAttrs({
        visible: true,
        x: Math.min(x1, x2),
        y: Math.min(y1, y2),
        width: Math.abs(x2 - x1),
        height: Math.abs(y2 - y1),
      })
    })

    self.stage.on('mouseup', (e) => {
      selecting = false
      if (!this.selectionRectangle.visible()) {
        return
      }
      e.evt.preventDefault()
      self.selectionRectangle.visible(false)
      // 去除一些不可被选中的图形
      let shapes = self.layer.find(node => {
        return !(node.attrs.className === 'selectionRectangle') &&
        !(node.hasName('_anchor')) && !(node === self.tr) &&
        !(node.attrs.name === 'back') &&
        !(node.attrs.type === 'line') &&
        !(node.attrs.type === 'lineGroup') &&
        !(node.attrs.isAnchor)
      })
      let box = self.selectionRectangle.getClientRect()
      let selected = shapes.filter((shape) =>
        Konva.Util.haveIntersection(box, shape.getClientRect())
      )
      self.setSelectDom(null)
      self.tr.nodes(selected)
    })

    // clicks should select/deselect shapes
    self.stage.on('click', function (e) {
      if (self.selectionRectangle.visible()) {
        return
      }

      if (e.target.attrs.isAnchor) {
        return
      }

      if (e.target === self.stage) {
        self.focusGraph(null)
        self.setSelectDom(null)
        self.tr.nodes([]);
        return
      }

      const isSelected = self.tr.nodes().indexOf(e.target) >= 0
      if (isSelected) {
        self.setSelectDom(null)
        self.focusGraph(null)
      } else {
        self.setSelectDom(e.target)
        self.focusGraph(e.target)
      }
    })
  }

  onDropLine(e) {
    const x = e.nativeEvent.layerX
    const y = e.nativeEvent.layerY
    const lineGroup = new Konva.Group({
      x,
      y,
      type: 'lineGroup',
      draggable: true,
    })
    const line = new Konva.Line({
      x: 0,
      y: 0,
      points: [0, 150, 150, 0],
      stroke: '#000000',
      strokeWidth: 5,
      type: 'line',
      draggable: false
    })
    lineGroup.add(line)
    this.layer.add(lineGroup)
    return line
  }
  
  onDropCustomeShape(e, createDragDom) {
    const x = e.nativeEvent.layerX
    const y = e.nativeEvent.layerY
    const shape = new Konva.Shape({
      pointInfo: {
        pointId: '',
        pointName: ''
      },
      offlineStatus: {
        stroke: 'rgba(189, 189, 189, 1)',
        fill: 'rgba(189, 189, 189, 1)',
      },
      valueMapping: [],
      width: createDragDom.width,
      height: createDragDom.height,
      x,
      y,
      strokeWidth: createDragDom.strokeWidth,
      stroke: '#000000',
      fill: createDragDom.fill,
      sceneFuncStr: createDragDom.sceneFuncStr,
      sceneFunc: new Function('context', 'shape', createDragDom.sceneFuncStr),
      type: 'customShape',
      shape: createDragDom.shape,
      draggable: true
    })
    this.layer.add(shape)
    return shape
  }
  
  onDropImage(e, createDragDom) {
    const x = e.nativeEvent.layerX
    const y = e.nativeEvent.layerY
    let imageNode
    const imageObj = new Image();
    imageObj.src = createDragDom.iconPath
    imageNode = new Konva.Image({
      x,
      y,
      image: imageObj,
      width: createDragDom.width,
      height: createDragDom.height,
      type: 'image',
      draggable: true
    })
    this.layer.add(imageNode);
    return imageNode
  }

  onDropBaseShape(e, createDragDom) {
    const x = e.nativeEvent.layerX
    const y = e.nativeEvent.layerY
    const node = new Konva[createDragDom.shape]({
      x,
      y,
      draggable: true,
      type: createDragDom.type,
      ...createDragDom.attrs
    })
    this.layer.add(node)
    return node
  }

  // 创建图形
  createGraph(e, createDragDom) {
    if (createDragDom) {
      switch(createDragDom.type) {
        case 'Line':
          return this.onDropLine(e)
        case 'CustomShape':
          return this.onDropCustomeShape(e, createDragDom)
        case 'Image':
          return this.onDropImage(e, createDragDom)
        default:
          return this.onDropBaseShape(e, createDragDom)
      }
    }
  }

  focusLine(lineGraph) {
    lineGraph.draw()
    const lineGroup = lineGraph.parent
    const anchorNodes = lineGroup.find(node => node.attrs.isAnchor)
    anchorNodes.forEach(node => node.destroy())
    const points = lineGraph.attrs.points

    console.log('创建结束，在此处记录undo步骤')
    // 处理路劲途径点
    let pointPath = []
    points.forEach((pt, ptIndex) => {
      if (ptIndex % 2 === 0) {
        const point = {
          x: pt,
          y: points[ptIndex + 1],
          ptIndex
        }
        pointPath.push(point)
      }
    })
    pointPath.forEach((pt, pathIndex) => {
      // pt的ptIndex是0 2 4 6 8 10这样的双倍
      // 添加半真实锚点
      if (pathIndex > 0) {
        const immediateAnchor = new Konva.Circle({
          x: (pt.x + pointPath[pathIndex - 1].x) / 2,
          y: (pt.y + pointPath[pathIndex - 1].y) / 2,
          radius: 5,
          stroke: 'rgba(102,102,102, 0.3)',
          fill: 'rgba(221,221,221, 0.3)',
          strokeWidth: 2,
          draggable: true,
          isAnchor: true
        })
        immediateAnchor.on('dragend', (e) => {
          // 重画线段路劲
          const newPoints = points.slice(0, pt.ptIndex).concat(e.target.attrs.x, e.target.attrs.y, points.slice(pt.ptIndex))
          lineGraph.attrs.points = newPoints
          this.focusLine(lineGraph)
        })
        lineGroup.add(immediateAnchor)
      }
      // 添加真实锚点
      const anchor = new Konva.Circle({
        x: pt.x,
        y: pt.y,
        radius: 5,
        stroke: '#666',
        fill: '#ddd',
        strokeWidth: 2,
        draggable: true,
        isAnchor: true
      })
      lineGroup.add(anchor)
      anchor.on('dragend', () => {
        // 修改线条路劲
        lineGraph.attrs.points[pt.ptIndex] = anchor.attrs.x
        lineGraph.attrs.points[pt.ptIndex + 1] = anchor.attrs.y
        this.focusLine(lineGraph)
      })
    })
  }

  focusNode(node) {
    this.tr.nodes([node])
  }

  focusGraph(graph) {
    // 清除线段的航点
    const nodes = this.layer.find(node => {
      return node.attrs.type === 'lineGroup'
    })
    if (nodes?.length) {
      nodes.forEach(node => {
        if (node.children?.length > 1) {
          const anchors = node.find('Circle')
          anchors.forEach(anchor => anchor.destroy())
        }
      })
    }
    // 清除所有的transformer
    this.tr.nodes([])
    if (graph) {
      switch(graph.attrs.type) {
        case 'line':
          this.focusLine(graph)
          break
        default:
          this.focusNode(graph)
      }
    }
  }
  
  deleteNodes(selectDom) {
    this.tr.nodes().forEach(node => {
      node.destroy()
    })
    this.tr.nodes([])
    if (selectDom) {
      if (selectDom.attrs.type === 'line') {
        const lineGroup = selectDom.parent
        lineGroup.destroy()
      } else {
        selectDom.destroy()
      }
    }
    this.setSelectDom(null)
    this.focusGraph(null)
  }
}